package com.github.limit.holder;

import com.github.limit.util.LimitUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: wangdejun
 * @create: 2019-10-12 17:36
 **/
@Slf4j
public abstract class AbstractLimitAnnotationHolder implements LimitAnnotationHolder {

    // method和限流的关系
    private static final Map<Method, List<Annotation>> methodAnnotationMap = new ConcurrentHashMap<>(64);

    public static final List<Annotation> getMethodAnnotations(Method method) {
        return methodAnnotationMap.get(method);
    }

    protected final void setMethodAnnotation(Method method, List<Annotation> annotations) {
        if (!methodAnnotationMap.containsKey(method)) {
            methodAnnotationMap.put(method, annotations);
            return;
        }

        mergeAndCover(method, annotations);

    }

    // 添加方法和注解的映射关系
    protected final void setMethodAnnotation(Method method, Annotation annotation) {
        if (!methodAnnotationMap.containsKey(method)) {
            List<Annotation> annotations = new ArrayList<>();
            annotations.add(annotation);
            setMethodAnnotation(method, annotations);
        } else {
            List<Annotation> annotations = new ArrayList<>();
            annotations.add(annotation);

            mergeAndCover(method, annotations);

        }
    }

    /**
     * 合并注解并覆盖老的注解
     *
     * @param method
     * @param annotations
     */
    private void mergeAndCover(Method method, List<Annotation> annotations) {
        // 获取之前添加的注解
        List<Annotation> annotationList = methodAnnotationMap.get(method);

        // 覆盖老的注解，并进行排序
        List<Annotation> mergeAndSort = LimitUtils.mergeAndSort(annotations, annotationList);

        // 将方法和注解的关系进行保存
        methodAnnotationMap.put(method, mergeAndSort);
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        ApplicationContext applicationContext = contextRefreshedEvent.getApplicationContext();
        if(contextRefreshedEvent.getApplicationContext() != null) {
            try {
                this.initMethodAnnotation(applicationContext);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("服务异常");
            }

        }
    }
}
